package com.crawler.waf.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver;
import org.springframework.util.ClassUtils;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;

import com.crawler.waf.exceptions.WafHandlerExceptionResolver;
import com.crawler.waf.exceptions.WafHandlerExceptionResolverBuilder;
import com.crawler.waf.exceptions.support.HttpMessageConverterUtils;
import com.crawler.waf.o2o.JacksonCustomObjectMapper;

import javax.xml.transform.Source;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * 基于spring mvc 注解方式进行配置Waf的spring配置。在本类中配置如下：<br>
 * 1、rest风格的数据转换器<br>
 * 2、异常配置资源加载<br>
 * 3、默认支持的ContentType<br>
 * 4、rest风格的异常处理器{@see WafHandlerExceptionResolver}<br>
 * 5、内部注解类的扫描路径配置<br>
 */
@Configuration
@ComponentScan(basePackages = {"com.crawler.waf.controllers"})
public class WafWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
    private static final boolean jaxb2Present =
            ClassUtils.isPresent("javax.xml.bind.Binder", WafWebMvcConfigurerAdapter.class.getClassLoader());

    private static final boolean jackson2Present =
            ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", WafWebMvcConfigurerAdapter.class.getClassLoader()) &&
                    ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", WafWebMvcConfigurerAdapter.class.getClassLoader());

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false).favorParameter(false);
        configurer.defaultContentType(MediaType.APPLICATION_JSON);
    }

    //增加媒体类型支持和数据转换类
    @Override
    public void configureMessageConverters(
            List<HttpMessageConverter<?>> converters) {

        //设置字符串转换默认编码为UTF-8
        StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
        stringConverter.setWriteAcceptCharset(false);

        converters.add(new ByteArrayHttpMessageConverter());
        converters.add(stringConverter);
        converters.add(new ResourceHttpMessageConverter());
        converters.add(new SourceHttpMessageConverter<Source>());
        converters.add(new AllEncompassingFormHttpMessageConverter());
//		if (romePresent) {
//			converters.add(new AtomFeedHttpMessageConverter());
//			converters.add(new RssChannelHttpMessageConverter());
//		}
        if (jaxb2Present) {
            Jaxb2RootElementHttpMessageConverter xmlConverter = new Jaxb2RootElementHttpMessageConverter();
            List<MediaType> supportedMediaTypes = new ArrayList<>();
            supportedMediaTypes.add(MediaType.APPLICATION_XML);
            xmlConverter.setSupportedMediaTypes(supportedMediaTypes);
            converters.add(xmlConverter);
        }
        if (jackson2Present) {
            MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
            messageConverter.setObjectMapper(new JacksonCustomObjectMapper());
            List<MediaType> supportedMediaTypes = new ArrayList<>();
            supportedMediaTypes.add(MediaType.APPLICATION_JSON);
            messageConverter.setSupportedMediaTypes(supportedMediaTypes);
            converters.add(messageConverter);
        }
        customMediaTypeSupport(converters);
    }

    public void customMediaTypeSupport(List<HttpMessageConverter<?>> converters) {
    }

    @Bean
    public WafHandlerExceptionResolver wafExceptionResolver() {
        WafHandlerExceptionResolverBuilder builder = WafHandlerExceptionResolver
                .builder();
        builder.setDefaultContentType(MediaType.APPLICATION_JSON);
        WafHandlerExceptionResolver resolver = builder.build();
        resolver.setOrder(-1);
        return resolver;
    }

    @Bean
    public ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver() {
        ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
        resolver.setMessageConverters(HttpMessageConverterUtils
                .getDefaultHttpMessageConverters());
        resolver.setOrder(-2);
        return resolver;
    }

    @Bean
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setDefaultEncoding("utf-8");
        resolver.setMaxUploadSize(5 * 1024 * 1024);
        resolver.setMaxInMemorySize(512 * 1024);
        //resolver.setResolveLazily(true);//屏蔽此参数提供多文件上传支持
        return resolver;
    }

	@Override
	public void addArgumentResolvers(
			List<HandlerMethodArgumentResolver> argumentResolvers) {
		argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
		super.addArgumentResolvers(argumentResolvers);
	}
    
    
}